#include <stdio.h>
#include <assert.h>
#include "sdlJeu.h"
#include "constante.h"
#include <time.h>
void SDL_apply_surface( SDL_Surface* source, SDL_Surface* destination, int x, int y );

SDL_Surface *SDL_load_image(const char* filename );


void sdlInit(sdlJeu *pSdlJeu)
{
    int dimX, dimY;

    jeuInit(&(pSdlJeu->jeu));

    if (SDL_Init(SDL_INIT_VIDEO) == -1) /* Démarrage de la SDL. Si erreur : */
    {
        fprintf(stderr, "Erreur d'initialisation de la SDL : %s\n", SDL_GetError()); /* Écriture de l'erreur */
        exit(EXIT_FAILURE); /* On quitte le programme */
    }


    dimX = terrainGetX( jeuGetConstTerrain(&(pSdlJeu->jeu)));
    dimY = terrainGetY( jeuGetConstTerrain(&(pSdlJeu->jeu)));
    dimX = dimX * TAILLE_SPRITE;
    dimY = dimY * TAILLE_SPRITE;

    pSdlJeu->ecran = SDL_SetVideoMode(LARGEUR_ECRAN, LONGUEUR_ECRAN, 32, SDL_HWSURFACE | SDL_RESIZABLE | SDL_DOUBLEBUF );

    assert( pSdlJeu->ecran!=NULL);
    SDL_WM_SetCaption( "Portal-like", NULL ); /* Permet de donner un nom à la fenêtre */

    pSdlJeu->surfaceTerrain = SDL_load_image("data/terrain.bmp");
    if (pSdlJeu->surfaceTerrain==NULL)
        pSdlJeu->surfaceTerrain = SDL_load_image("../data/terrain.bmp");


    pSdlJeu->surfacePersonnage = SDL_load_image("data/personnage.bmp");
    if (pSdlJeu->surfacePersonnage==NULL)
        pSdlJeu->surfacePersonnage = SDL_load_image("../data/personnage.bmp");
    assert( pSdlJeu->surfacePersonnage !=NULL);

    /* Gerer Ennemi */
    pSdlJeu->surfaceEnnemi = SDL_load_image("data/ennemie.bmp");
    if (pSdlJeu->surfaceEnnemi==NULL)
        pSdlJeu->surfaceEnnemi = SDL_load_image("../data/ennemie.bmp");
    assert( pSdlJeu->surfaceEnnemi !=NULL);

    pSdlJeu->surfacePortailOrange = SDL_load_image("data/terrain.bmp");
    if (pSdlJeu->surfacePortailOrange==NULL)
        pSdlJeu->surfacePortailOrange = SDL_load_image("../data/terrain.bmp");
    assert( pSdlJeu->surfacePortailOrange!=NULL);

    pSdlJeu->surfacePortailRouge = SDL_load_image("data/terrain.bmp");
    if (pSdlJeu->surfacePortailRouge==NULL)
        pSdlJeu->surfacePortailRouge = SDL_load_image("../data/terrain.bmp");
    assert( pSdlJeu->surfacePortailRouge!=NULL);

    /* chargement des elements du terain */
    /* Les coordonnées x et y définissent le point en haut à gauche du rectangle */
    pSdlJeu->rectTerrain[0].h = TAILLE_SPRITE; /* hauteur */
    pSdlJeu->rectTerrain[0].w = TAILLE_SPRITE; /* longueur */
    pSdlJeu->rectTerrain[0].x = 3*TAILLE_SPRITE; /* coordonnée x, on choisit la 4 ème case (colonne) de "terrain.bmp" */
    pSdlJeu->rectTerrain[0].y = 0*TAILLE_SPRITE;/* coordonnée y, de la première ligne */

    pSdlJeu->rectTerrain[1].h = TAILLE_SPRITE;
    pSdlJeu->rectTerrain[1].w = TAILLE_SPRITE;
    pSdlJeu->rectTerrain[1].x = 2*TAILLE_SPRITE;
    pSdlJeu->rectTerrain[1].y = 0*TAILLE_SPRITE;


    pSdlJeu->rectTerrain[2].h = TAILLE_SPRITE;
    pSdlJeu->rectTerrain[2].w = TAILLE_SPRITE;
    pSdlJeu->rectTerrain[2].x = 14*TAILLE_SPRITE;
    pSdlJeu->rectTerrain[2].y = 0*TAILLE_SPRITE;

    /* rect pour le personnage */

    pSdlJeu->rectPersonnage.h = TAILLE_SPRITE;
    pSdlJeu->rectPersonnage.w = TAILLE_SPRITE;
    /*rect pour les enemies */

    pSdlJeu->rectEnnemi.h = TAILLE_SPRITE;
    pSdlJeu->rectEnnemi.w = TAILLE_SPRITE;

    /* rect pour les portails */

    pSdlJeu->rectPortailRouge.h = 1.0 * TAILLE_SPRITE;
    pSdlJeu->rectPortailRouge.w = 1.0 * TAILLE_SPRITE;
    pSdlJeu->rectPortailRouge.x = 14 * TAILLE_SPRITE;
    pSdlJeu->rectPortailRouge.y = 14 * TAILLE_SPRITE;

    pSdlJeu->rectPortailOrange.h = 1.0 * TAILLE_SPRITE;
    pSdlJeu->rectPortailOrange.w = 1.0 * TAILLE_SPRITE;
    pSdlJeu->rectPortailOrange.x = 14 * TAILLE_SPRITE;
    pSdlJeu->rectPortailOrange.y = 12 * TAILLE_SPRITE;


}

void sdlAffichage(sdlJeu *pSdlJeu)
{
    int x,y, posx, posy, maxx, maxy, minx, miny,i ;

    int dimX = terrainGetX(jeuGetConstTerrain(&(pSdlJeu->jeu)));
    int dimY = terrainGetY(jeuGetConstTerrain(&(pSdlJeu->jeu)));

    const Jeu *pJeu = &(pSdlJeu->jeu);

    SDL_Rect rectPerso, rectTer, rectEnnemi , rectPortail1 , rectPortail2;

    /* Remplir l'écran de blanc */
    /*  SDL_FillRect( pSdlJeu->ecran, &pSdlJeu->ecran->clip_rect, SDL_MapRGB( pSdlJeu->ecran->format, 255, 255, 255 ) ); */


    posx = (int)(personnageGetPosX(jeuGetConstPersonnage(pJeu))*TAILLE_SPRITE);
    posy = (int)(personnageGetPosY(jeuGetConstPersonnage(pJeu))*TAILLE_SPRITE);

    maxx = (posx + LARGEUR_ECRAN/2)/(TAILLE_SPRITE-1);
    maxy = (posy + LARGEUR_ECRAN/2)/(TAILLE_SPRITE-1);

    minx = posx / ((TAILLE_SPRITE-1)+(LARGEUR_ECRAN/2));
    miny = posx / ((TAILLE_SPRITE-1)+(LARGEUR_ECRAN/2));

    rectPerso.x = LARGEUR_ECRAN/2;
    rectPerso.y = LONGUEUR_ECRAN/2;


    /* Remplir l'écran de blanc */
    SDL_FillRect( pSdlJeu->ecran, &pSdlJeu->ecran->clip_rect, SDL_MapRGB( pSdlJeu->ecran->format, 0, 0, 0 ) );
    /* SDL_FillRect( pSdlJeu->ecran, &pSdlJeu->ecran->clip_rect, SDL_MapRGB( pSdlJeu->ecran->format, 255, 255, 255 ) );*/
    for (x=minx; x<maxx; ++x)
    {
        for (y=miny; y<maxy; ++y)
        {
            rectTer.x = ((LARGEUR_ECRAN/2) + x*TAILLE_SPRITE) - posx;
            rectTer.y = ((LONGUEUR_ECRAN/2) + y*TAILLE_SPRITE) - posy;

            if((x>=0 ) && (y>=0) && (y<dimY) && (x<dimX))
                SDL_BlitSurface(pSdlJeu->surfaceTerrain,&(pSdlJeu->rectTerrain[terrainGetCase(jeuGetConstTerrain(&(pSdlJeu->jeu)), x, y)]),pSdlJeu->ecran,&rectTer);

        }
    }
    if(vectGetX(&(pSdlJeu->jeu.personnage.vitesse))>0) /* Le personnage se déplace vers la droite * const vect */
    {
        pSdlJeu->rectPersonnage.x = 1*TAILLE_SPRITE;
        pSdlJeu->rectPersonnage.y = 2*TAILLE_SPRITE;
    }
    else if (vectGetX(&(pSdlJeu->jeu.personnage.vitesse))<0) /* Le personnage se déplace vers la gauche */
    {
        pSdlJeu->rectPersonnage.x = 1*TAILLE_SPRITE;
        pSdlJeu->rectPersonnage.y = 1*TAILLE_SPRITE;
    }
    else
    {
        pSdlJeu->rectPersonnage.x = 1*TAILLE_SPRITE; /* Le personnage ne se déplace pas */
        pSdlJeu->rectPersonnage.y = 0*TAILLE_SPRITE;
    }

	SDL_SetColorKey(pSdlJeu->surfacePersonnage, SDL_SRCCOLORKEY, SDL_MapRGB(pSdlJeu->surfacePersonnage->format, 0, 0, 0));
    /* On enlève le blanc qui entoure le personnage dans sa case */
    SDL_BlitSurface(pSdlJeu->surfacePersonnage,&(pSdlJeu->rectPersonnage),pSdlJeu->ecran,&rectPerso);
    /* On affiche le personnage */
    SDL_Flip(pSdlJeu->ecran);
    /* Permet de passer d'un écran à l'autre*/
    /* void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h); qui met à jour qu'une partie de l'écran -> plus rapide mais peux pas utiliser le double buffering */
    for(i=0; i< pJeu->nbEnnemis; i++)
    {

        rectEnnemi.x = (int)((LARGEUR_ECRAN/2)  + personnageGetPosX( &(jeuGetConstEnnemi(pJeu,i)->ennemi) )* TAILLE_SPRITE) - posx;
        rectEnnemi.y = (int)((LONGUEUR_ECRAN/2) + personnageGetPosY( &(jeuGetConstEnnemi(pJeu,i)->ennemi) )* TAILLE_SPRITE)- posy;

        pSdlJeu->rectEnnemi.x = 6*TAILLE_SPRITE;
        pSdlJeu->rectEnnemi.y = 4*TAILLE_SPRITE;

		SDL_SetColorKey(pSdlJeu->surfaceEnnemi, SDL_SRCCOLORKEY, SDL_MapRGB(pSdlJeu->surfaceEnnemi->format, 0, 0, 0));
        SDL_BlitSurface(pSdlJeu->surfaceEnnemi,&(pSdlJeu->rectEnnemi),pSdlJeu->ecran,&rectEnnemi);


    }

    /* affichage des portails */

    rectPortail1.x = (int)(((LARGEUR_ECRAN/2) + (pJeu->tabPortails[0].x)*TAILLE_SPRITE) - posx);
    rectPortail1.y = (int)(((LONGUEUR_ECRAN/2) + (pJeu->tabPortails[0].y)*TAILLE_SPRITE) - posy);

    rectPortail2.x = (int)((LARGEUR_ECRAN/2) + (pJeu->tabPortails[1].x)*TAILLE_SPRITE - posx);
    rectPortail2.y = (int)((LONGUEUR_ECRAN/2) + (pJeu->tabPortails[1].y)*TAILLE_SPRITE - posy);


    /* if(pJeu->tabPortails[0] != NULL) */
    SDL_BlitSurface(pSdlJeu->surfacePortailRouge ,&(pSdlJeu->rectPortailRouge), pSdlJeu->ecran,&rectPortail1);
    SDL_BlitSurface(pSdlJeu->surfacePortailOrange ,&(pSdlJeu->rectPortailOrange), pSdlJeu->ecran,&rectPortail2);


    SDL_Flip(pSdlJeu->ecran);
    /* Permet de passer d'un écran à l'autre*/
    /* void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h); qui met à jour qu'une partie de l'écran -> plus rapide mais peux pas utiliser le double buffering */


}

void sdlBoucle(sdlJeu *pSdlJeu)
{
    SDL_Event event;
    int continue_boucle = 1;
    float horloge_courante, horloge_precedente;
    float intervalle_horloge = 0.001f;
    int rafraichissement;
    int action, saut= 0;



    sdlAffichage(pSdlJeu);
    assert( SDL_Flip( pSdlJeu->ecran )!=-1 ); /* Vérifie que l'écran est bien initialisé */

    horloge_precedente = (float)clock()/(float)CLOCKS_PER_SEC;

    while ( continue_boucle == 1 )
    {
        rafraichissement = 0;
        horloge_courante = (float)clock()/(float)CLOCKS_PER_SEC;

        while ( SDL_PollEvent( &event ) ) /* Tant Qu'il y a des évènements en attente, retourne 1, retourne 0 s'il n'y en a pas de disponible. */
        {

            if ( event.type == SDL_QUIT )/* Si l'utilisateur a cliqué sur la croix de fermeture */
                continue_boucle = 0;

            if ( event.type == SDL_KEYDOWN )/* Si l'utilisateur a appuyé sur une touche */
            {
                switch ( event.key.keysym.sym ) /* suivant le touche appuyée */
                {
                case SDLK_ESCAPE :
                    continue_boucle = 0;
                    break;
                case SDLK_SPACE:
                    rafraichissement = 1;
                    saut = 1;
                    break;

                case SDLK_q:
                    rafraichissement = 1;
                    action = 'g';
                    break;

                case SDLK_d:
                    action = 'd';
                    rafraichissement = 1;
                    break;
                case SDLK_LSHIFT:
                    rafraichissement = 1;
                    personnageSetCourse(&(pSdlJeu->jeu.personnage), 1);
                    break;
                default :
                    action = 0;
                    break;

                }
            }
            if ( event.type == SDL_KEYUP )/* Si l'utilisateur a appuyé sur une touche */
            {
                switch ( event.key.keysym.sym ) /* suivant le touche appuyée */
                {
                case SDLK_SPACE:
                    rafraichissement = 1;
                    break;

                case SDLK_q:
                    if(action == 'g')
                        action = 0;
                    rafraichissement = 1;
                    break;

                case SDLK_d:
                    if(action == 'd')
                        action = 0;
                    rafraichissement = 1;
                    break;
                case SDLK_LSHIFT:
                    rafraichissement = 1;
                    personnageSetCourse(&(pSdlJeu->jeu.personnage), 0);
                    break;
                default :
                    break;

                }
            }

            else
            {

                rafraichissement = 1;
            }
        }

        if (horloge_courante-horloge_precedente>=intervalle_horloge)
        {

            jeuEvolue(&(pSdlJeu->jeu));
            if(saut)
            {
                jeuActionClavier(&(pSdlJeu->jeu), 's');
                saut = 0;
            }
            if (action==0)
                personnageDeceleration(&(pSdlJeu->jeu.personnage));
            else
            {
                jeuActionClavier( &(pSdlJeu->jeu), action);
            }
            rafraichissement = 1;
            horloge_precedente = horloge_courante;
        }

        if (rafraichissement==1)
        {
            /* on affiche le jeu sur le buffer caché */
            sdlAffichage(pSdlJeu);

            /* on permute les deux buffers (cette fonction ne doit se faire qu'une seule fois dans a boucle) */
            SDL_Flip( pSdlJeu->ecran );
        }
    }
}

SDL_Surface *SDL_load_image(const char* filename )
{
    /* Temporary storage for the image that's loaded */
    SDL_Surface* loadedImage = NULL;

    /* The optimized image that will be used */
    SDL_Surface* optimizedImage = NULL;

    /* Load the image */
    loadedImage = SDL_LoadBMP( filename );

    /* If nothing went wrong in loading the image */
    if ( loadedImage != NULL )
    {
        /* Create an optimized image */
        optimizedImage = SDL_DisplayFormat( loadedImage );

        /* Free the old image */
        SDL_FreeSurface( loadedImage );
    }

    /* Return the optimized image */
    return optimizedImage;
}

void sdlPause()
{
    int continuer = 1;
    SDL_Event event;

    while (continuer)
    {
        SDL_WaitEvent(&event);
        switch(event.type)
        {
        case SDL_QUIT:
            continuer = 0;
        }
    }
}

/**
 * @brief Testamente une  structure sdlJeu initialisé
 *
*/
void sdlTestament(sdlJeu * psdlJeu)
{


    SDL_FreeSurface(psdlJeu->ecran);
    SDL_FreeSurface(psdlJeu->surfaceTerrain);
    SDL_FreeSurface(psdlJeu->surfacePersonnage);
    SDL_FreeSurface(psdlJeu->surfaceEnnemi);
    SDL_FreeSurface(psdlJeu->surfacePortailRouge);
    SDL_FreeSurface(psdlJeu->surfacePortailOrange);

    SDL_Quit();

    jeuTestament(&psdlJeu->jeu);
}


